package com.aiyige.richtexteditor;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.webkit.JavascriptInterface;
import android.widget.FrameLayout;

import com.aiyige.R;
import com.aiyige.base.JSNativeEvent;
import com.aiyige.base.JSNativeResponse;
import com.aiyige.page.publish.util.PublishUtil;
import com.aiyige.richtexteditor.model.RTELocalMedia;
import com.aiyige.richtexteditor.model.RTEModel;
import com.aiyige.richtexteditor.util.RichTextUtil;
import com.aiyige.utils.EventBusUtil;
import com.aiyige.utils.SafeAsyncTask;
import com.aiyige.utils.ToastX;
import com.aiyige.utils.UUIDUtil;
import com.aiyige.utils.VideoUtil;
import com.aiyige.utils.WebViewUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.luck.picture.lib.PictureSelector;
import com.luck.picture.lib.config.PictureConfig;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.entity.LocalMedia;
import com.tencent.smtt.sdk.WebChromeClient;
import com.tencent.smtt.sdk.WebView;
import com.tencent.smtt.sdk.WebViewClient;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class RichTextEditor extends FrameLayout {
    public static final String TAG = RichTextEditor.class.getSimpleName();
    public static final int REQUEST_CODE_INSERT_IMAGE = 0xb750;
    public static final int REQUEST_CODE_INSERT_VIDEO = 0xdd17;
    WebView webView;
    FragmentActivity activity;
    RTEModel model;
    Callback callback;
    Handler mainHandler;

    public RichTextEditor(@NonNull Context context) {
        super(context);
        init();
    }

    public RichTextEditor(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public RichTextEditor(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        LayoutInflater.from(getContext()).inflate(R.layout.rich_text_editor, this, true);
        webView = findViewById(R.id.webView);
        model = RTEModel.newBuilder().build();
        callback = null;
        mainHandler = new Handler(Looper.getMainLooper());
        initWebview();
        initJavaScriptObject();
    }

    public void setData(RTEModel rteModel) {
        this.model = new RTEModel(rteModel);
    }

    private void initWebview() {
        webView.setWebChromeClient(createWebChromeClient());
        webView.setWebViewClient(createWebViewClient());
        webView.getSettings().setAllowContentAccess(true);
        webView.getSettings().setAllowFileAccess(true);
        webView.getSettings().setAppCacheEnabled(true);
        webView.getSettings().setJavaScriptEnabled(true);
        webView.getSettings().setDomStorageEnabled(true);
        webView.getSettings().setAppCacheMaxSize(Long.MAX_VALUE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            webView.getSettings().setAllowFileAccessFromFileURLs(true);
            webView.getSettings().setAllowUniversalAccessFromFileURLs(true);
        }
    }

    private WebViewClient createWebViewClient() {
        return new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                String safeUrl = url.toLowerCase();
                if (safeUrl.startsWith("http") || safeUrl.startsWith("https") || safeUrl.startsWith("file")) {
                    return super.shouldOverrideUrlLoading(view, url);
                } else {
                    return true;
                }
            }
        };
    }

    private WebChromeClient createWebChromeClient() {
        return new WebChromeClient();
    }

    public Callback getCallback() {
        return callback;
    }

    public void setCallback(Callback callback) {
        this.callback = callback;
    }

    public void onCreate(FragmentActivity activity) {
        this.activity = activity;
    }

    public void loadEditor() {
        webView.loadUrl("file:///android_asset/RichTextEditor/richtexteditor.html");
    }

    public void onDestroy() {
    }

    public void onPause() {
        webView.onPause();
    }

    public void onResume() {
        webView.onResume();
    }


    public void initJavaScriptObject() {
        webView.addJavascriptInterface(new JavaScriptObject(), "android");
    }


    public class JavaScriptObject {
        @JavascriptInterface
        public void contentReceived(String json) {
            try {
                JSNativeResponse response = JSON.parseObject(json, JSNativeResponse.class);
                if (JSNativeResponse.RESULT_SUCCESS.equals(response.getResult())) {
                    JSONObject jsonObject = JSON.parseObject(response.getData());
                    String html = jsonObject.getString("htmlContent");
                    model.setContent(html);
                    try {
                        List<String> mediaIdList = JSON.parseArray(jsonObject.getString("mediaIds"), String.class);
                        model.setRteLocalMediaList(RichTextUtil.alignRTELocalMediaList(model.getRteLocalMediaList(), mediaIdList));
                    } catch (Exception e) {
                        model.setRteLocalMediaList(new LinkedList<RTELocalMedia>());
                    }
                    if (callback != null) {
                        callback.contentReceived(model);
                    }
                }
            } catch (Exception e) {
            }
        }

        @JavascriptInterface
        public String onNativeEvent(String json) {
            try {
                final JSNativeEvent event = JSON.parseObject(json, JSNativeEvent.class);
                switch (event.getEventType()) {
                    case JSNativeEvent.EVENT_TYPE_TOAST: {
                        if (!TextUtils.isEmpty(event.getData())) {
                            mainHandler.post(new Runnable() {
                                @Override
                                public void run() {
                                    ToastX.show(event.getData());
                                }
                            });
                        }
                        return JSON.toJSONString(JSNativeResponse.newBuilder()
                                .result(JSNativeResponse.RESULT_SUCCESS)
                                .build());
                    }
                    case JSNativeEvent.EVENT_TYPE_NOTIFY_CONTENT_EMPTY: {
                        mainHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                boolean empty;
                                try {
                                    empty = Boolean.valueOf(event.getData());
                                } catch (Exception e) {
                                    empty = true;
                                }
                                model.setEmpty(empty);
                                if (callback != null) {
                                    callback.notifyContentEmpty(empty);
                                }
                            }
                        });
                        return JSON.toJSONString(JSNativeResponse.newBuilder()
                                .result(JSNativeResponse.RESULT_SUCCESS)
                                .build());
                    }
                    case JSNativeEvent.EVENT_TYPE_INSERT_IMAGE:
                        PictureSelector.create(activity)
                                .openGallery(PictureMimeType.ofImage())
                                .minSelectNum(1)
                                .selectionMode(PictureConfig.SINGLE)
                                .previewImage(false)
                                .enableCrop(false)
                                .isCamera(true)
                                .compress(false)
                                .isGif(true)
                                .imageSpanCount(4)
                                .forResult(REQUEST_CODE_INSERT_IMAGE);
                        return JSON.toJSONString(JSNativeResponse.newBuilder()
                                .result(JSNativeResponse.RESULT_SUCCESS)
                                .build());
                    case JSNativeEvent.EVENT_TYPE_INSERT_VIDEO:
                        PictureSelector.create(activity)
                                .openGallery(PictureMimeType.ofVideo())
                                .isCamera(false)
                                .previewImage(false)
                                .previewVideo(false)
                                .minSelectNum(1)
                                .selectionMode(PictureConfig.SINGLE)
                                .maxSize(PublishUtil.MAX_PUBLISH_VIDEO_SIZE)
                                .forResult(REQUEST_CODE_INSERT_VIDEO);
                        return JSON.toJSONString(JSNativeResponse.newBuilder()
                                .result(JSNativeResponse.RESULT_SUCCESS)
                                .build());

                    case JSNativeEvent.EVENT_TYPE_GET_CONTENT:
                        mainHandler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                insertContent(model.getContent());
                            }
                        }, 500);
                        return JSON.toJSONString(JSNativeResponse.newBuilder()
                                .result(JSNativeResponse.RESULT_SUCCESS)
                                .build());

                    default:
                        throw new Exception("");
                }
            } catch (Exception e) {
                return JSON.toJSONString(JSNativeResponse.newBuilder()
                        .result(JSNativeResponse.RESULT_FAILED)
                        .build());
            }
        }
    }


    public void insertContent(String html) {
        Map<String, Object> map = new HashMap<>();
        Map<String, String> data = new HashMap<>();
        data.put("htmlContent", html);
        data.put("jsonContent", "");
        map.put("eventType", JSNativeEvent.EVENT_TYPE_SET_CONTENT);
        map.put("data", data);
        WebViewUtil.callJsMethod(webView, "onH5Event", JSON.toJSONString(map));
    }

    public void requestContent() {
        WebViewUtil.callJs(webView, "android&&android.contentReceived(onH5Event(" + JSON.toJSONString(JSNativeEvent.newBuilder().eventType(JSNativeEvent.EVENT_TYPE_GET_CONTENT).build()) + "))");
    }

    public void insertImageToEditor(String imagePath) {
        RTELocalMedia rteLocalMedia = RTELocalMedia.newBuilder()
                .type(RTELocalMedia.TYPE_PHOTO)
                .mediaId(UUIDUtil.generate())
                .photoUrl(imagePath)
                .build();
        model.getRteLocalMediaList().add(rteLocalMedia);
        Map<String, Object> map = new HashMap<>();
        Map<String, String> data = new HashMap<>();
        data.put("imagePath", "file://" + rteLocalMedia.getPhotoUrl());
        data.put("id", rteLocalMedia.getMediaId());
        map.put("eventType", "insertImage");
        map.put("data", data);
        WebViewUtil.callJsMethod(webView, "onH5Event", JSON.toJSONString(map));
    }

    public void insertVideoToEditor(String videoPath, String[] coverPath) {
        RTELocalMedia rteLocalMedia = RTELocalMedia.newBuilder()
                .type(RTELocalMedia.TYPE_VIDEO)
                .mediaId(UUIDUtil.generate())
                .videoOriginalCoverUrl(coverPath[0])
                .videoCoverUrl(coverPath[1])
                .videoUrl(videoPath)
                .build();
        model.getRteLocalMediaList().add(rteLocalMedia);
        Map<String, Object> map = new HashMap<>();
        Map<String, String> data = new HashMap<>();
        data.put("coverPath", "file://" + rteLocalMedia.getVideoOriginalCoverUrl());
        data.put("videoPath", "file://" + rteLocalMedia.getVideoUrl());
        data.put("id", rteLocalMedia.getMediaId());
        map.put("eventType", "insertVideo");
        map.put("data", data);
        WebViewUtil.callJsMethod(webView, "onH5Event", JSON.toJSONString(map));
    }


    public class InsertVideoTask extends SafeAsyncTask<Object, Object, Object> {
        String videoPath;
        String[] coverPath;

        public InsertVideoTask(Activity activity, String videoPath) {
            super(activity, R.string.text_process);
            this.videoPath = videoPath;
        }

        @Override
        protected Object doInBackground(Object... objects) {
            try {
                coverPath = VideoUtil.getVideoCover(videoPath, 0, 600, 400, R.drawable.home_play);
                return null;
            } catch (Exception e) {
                return e;
            }
        }

        @Override
        public void safeOnPostExecute(Object o) {
            if (o instanceof Exception) {
                ToastX.show(((Exception) o).getMessage());
            } else {
                insertVideoToEditor(videoPath, coverPath);
            }
        }
    }


    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case REQUEST_CODE_INSERT_IMAGE:
                if (resultCode == Activity.RESULT_OK) {
                    List<LocalMedia> selectList = PictureSelector.obtainMultipleResult(data);
                    String filePath = selectList.get(0).getPath();
                    insertImageToEditor(filePath);
                }
                break;
            case REQUEST_CODE_INSERT_VIDEO:
                if (resultCode == Activity.RESULT_OK) {
                    List<LocalMedia> selectList = PictureSelector.obtainMultipleResult(data);
                    String filePath = selectList.get(0).getPath();
                    new InsertVideoTask(activity, filePath).execute();
                }
                break;
        }
    }

    public interface Callback {
        void notifyContentEmpty(boolean empty);

        void contentReceived(RTEModel model);
    }
}
